package com.myblog.adkblog.handler;

import com.myblog.adkblog.common.redis.SseNotify;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;

@Slf4j
@Component
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
public class SqlIntercept implements Interceptor {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 执行SQL语句
        Object result = invocation.proceed();
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        // 使用 MetaObject 获取 MappedStatement
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        Method mapperMethod = getMapperMethod(mappedStatement);
        if (mapperMethod != null) {
            SseNotify sseNotify = mapperMethod.getAnnotation(SseNotify.class);
            if (sseNotify != null) {
                String tableName = sseNotify.tableName();
                String clientId = sseNotify.clientId();
                String sql = statementHandler.getBoundSql().getSql();
                if (sql.toLowerCase().contains(tableName)) {
                    redisTemplate.convertAndSend("sse-notify", clientId);
                }
            }
        }
        return result;
    }

    private Method getMapperMethod(MappedStatement mappedStatement) throws ClassNotFoundException {
        String methodName = mappedStatement.getId();
        String className = methodName.substring(0, methodName.lastIndexOf("."));
        String methodNameOnly = methodName.substring(methodName.lastIndexOf(".") + 1);
        Class<?> mapperClass = Class.forName(className);
        for (Method method : mapperClass.getMethods()) {
            if (method.getName().equals(methodNameOnly)) {
                return method;
            }
        }
        return null;
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
